package comms;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.util.Vector;
import java.util.Enumeration;

import javax.microedition.io.Connector;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.ServerSocketConnection;

import ap.*;
import agent.*;

public class SocketAgentConnection extends Thread implements AgentConnection {
	private ConnectionManager owner;
	private SocketConnection currentConnection;
	private ServerSocketConnection currentServerConnection;
	private Vector connectionHandlers;
	private int connectionStatus;
	private boolean listening;
	private InputStream inStream;
	private OutputStream outStream;

	public SocketAgentConnection(ConnectionManager manager, String address, String port) {
		this.owner = manager;
		this.currentConnection = null;
		this.currentServerConnection = null;
		this.connectionHandlers = null;
		
		if (address.length() > 0) {
			this.connectionStatus = AgentConnection.SENDER_ONLY;
			this.listening = false;
			try {
				this.currentConnection = (SocketConnection)Connector.open("socket://" + address + ":" + port);
				this.currentConnection.setSocketOption(SocketConnection.LINGER, 5);
				this.inStream = this.currentConnection.openInputStream();
				this.outStream = this.currentConnection.openOutputStream();
			} catch (IOException e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
			}
		} else {
			this.connectionStatus = AgentConnection.RECEIVER_ONLY;
			this.listening = true;
			try {
				this.currentServerConnection = (ServerSocketConnection)Connector.open("socket://:" + port);
				this.inStream = null;
				this.outStream = null;
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			this.start();
		}	
	}
	
	public void run() {
		this.connectionHandlers = new Vector();
		
		while (listening && ((this.connectionStatus == AgentConnection.RECEIVER_ONLY) || (this.connectionStatus == AgentConnection.SENDER_RECEIVER))) {
			try {
				System.out.println("Waiting for connections.");
				this.currentConnection = (SocketConnection)this.currentServerConnection.acceptAndOpen();
				System.out.println("Connection established.");
				this.connectionHandlers.addElement(new SocketAgentConnectionHandler(this.owner, this.currentConnection));
			} catch (IOException e) {
				System.err.println(e.getMessage());
				e.printStackTrace();
			}
		}
	}
	
	public boolean sendAgent(MeetingAgent agent) throws AgentConnectionException {
	/*	boolean sent = false;
		
		if ((this.connectionStatus == AgentConnection.RECEIVER_ONLY) ||
				(this.connectionStatus == AgentConnection.CLOSED))
				throw new AgentConnectionException("Connection closed or not in send mode.");
		
		//TODO: implement using persistance/agent interface
		try {	
			this.outStream.write(agent.getDescription().getBytes());
			this.outStream.flush();
			sent = true;
		} catch (IOException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
		
		return sent;*/
		return true;//THIS IS A HACK
	}
	
	public boolean sendAgent(AgentPkt agentPack) throws AgentConnectionException {
		boolean sent = false;
		
		if ((this.connectionStatus == AgentConnection.RECEIVER_ONLY) ||
				(this.connectionStatus == AgentConnection.CLOSED))
				throw new AgentConnectionException("Connection closed or not in send mode.");
		
		try {	
			this.outStream.write(agentPack.getAgentString().getBytes());
			this.outStream.flush();
			sent = true;
			this.outStream.close();
		} catch (IOException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
		
		return sent;
	}
	
	public void closeConnection() {
		this.listening = false;
		this.connectionStatus = AgentConnection.CLOSED;
		
		try {
			if (this.inStream != null) this.inStream.close();
			if (this.outStream != null) this.outStream.close();
			if (this.currentServerConnection != null) this.currentServerConnection.close();
			if (this.currentConnection != null) this.currentConnection.close();
			if (this.connectionHandlers != null) {
				for (Enumeration e = this.connectionHandlers.elements(); e.hasMoreElements(); ) {
					((SocketAgentConnectionHandler)e.nextElement()).close();
				}
			}
		} catch (IOException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
	}
	
	public int getStatus() {
		return this.connectionStatus;
	}
 }
